# -*- encoding:utf-8 -*-
# @Date  :2016-07-12
# @Author:金忠帅|二条（jinzhongshuai#antiy.cn）
import os
import re
import os.path
import copy
import base64
import json
import binascii
import calendar
import datetime
import hashlib
import logging.handlers
from logging.handlers import TimedRotatingFileHandler, RotatingFileHandler


import signal
import string
import sys
import time
import urllib
import zipfile
from datetime import timedelta
from functools import update_wrapper, wraps

import requests
from pykafka import KafkaClient
from elasticsearch import Elasticsearch
from flask import request, Response, send_from_directory, current_app, url_for, make_response
from openpyxl import load_workbook


from config import config

reload(sys)
sys.setdefaultencoding('utf-8')


# 监测日志 excel批量导出 日志拆分
def get_events_info(info):
    return {
        # 发生时间
        "ts": info.get("ts", ""),
        # 日志id
        "id": info.get("id", ""),
        # 日志类型
        "stype": info.get("stype", ""),
        # 系统名称
        "sys_name": info.get("sys_info", {}).get("name", "") or '',
        # 所属机构
        "unit": info.get("sys_info", {}).get("unit", "") or '',
        "sip": "",
        "dip": "", 
        "proto": "",
        "md5": "",
        "malname": "",
        "virus_family": "",
        "url": "",
        "host": "",
        "load_md5": "",
        "vul_name": "",
        "vul_url": "",
        "cve_id": "", 
        "dev_name": "",
        "status": "",
        "op_result": "",
        "op_ts": ""
    }


# 构建Webray各种数据结构
class CreateWebrayJson(object):
    def __init__(self, website_name=None, site=None, level=0):
        # 网站名称、链接
        self.site = site
        self.search = {
            "r_time": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            "ts": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            "task_id": "",
            "task_name": "",
            "task_type": "",
            "alert_status": "none",
            "mfsr": "antiy",
            "level": level,
            "engine": ["antiy"],
            "site_info": {
                "name": website_name,
                "level": level,
                "ip": None,
                "institution": "",
                "person": "",
                "state": None,
                "id": ""
            },
            "site": site,
            "label": [],
            "type": "",
            "stype": "",
            "etype": [],
            "final_result": True,
            "url": [site],
            "id": "",
            "server_ip": "",
            "domain": [],
            "person_upload": 1,
        }

    def createVisible(self, dataType=None, resTime=None, lastRes=None):
        """构建可用性数据"""
        _search = copy.deepcopy(self.search)
        _search
        if dataType == 'http':
            _search["label"].append("http可用性")
            _search["visible_time"] = resTime
            _search["stype"] = "visible_http"
        elif dataType == 'dns':
            _search["label"].append("dns可用性")
            _search["visible_time"] = resTime
            _search["stype"] = "visible_dns"
        else:
            _search["label"].append("ping可用性")
            _search["visible_time"] = resTime
            _search["stype"] = "visible_ping"

        _search["etype"].append("web_visible")
        _search["type"] = "visible"
        _search["ts"] = lastRes
        _search["pid"] = "UPDATE"
        _search["id"] = calc_md5(json.dumps(_search))

        return _search

    def createTrojanFishDarklink(self, dataType=None, g_url=None, link=None,
                                 wm_type=None, wm_info=None, title=None):
        """构建暗链、挂马、钓鱼数据"""
        _search = copy.deepcopy(self.search)
        if dataType == 'trojan':
            _search["stype"] = "threat_trojan"
            _search["label"].append("挂马")
            _search["wm_type"] = wm_type
            _search["wm_infor"] = wm_info
            _search["url"].append(g_url)

        elif dataType == 'phish':
            _search["stype"] = "threat_phish"
            _search["label"].append("钓鱼")
            _search["title"] = title

        elif dataType == 'darklink':
            _search["stype"] = "darklink"
            _search["label"].append("暗链")

        _search["pid"] = "UPDATE"
        _search["g_url"] = g_url
        _search["link"] = link
        _search["type"] = "threat"
        _search["etype"].append("web_threat")
        _search["id"] = calc_md5(json.dumps(_search))
        return _search

    def createVul(self, dataType=None, vul_name=None, numbering=None, g_url=None):
        """构建漏洞数据"""
        _search = copy.deepcopy(self.search)
        if dataType == "web_vul":
            _search["label"].append("web漏洞")
            _search["stype"] = "web_vul"
            _search["vulns"] = {
                "name": vul_name,
                "solution": "",
                "desc": ""
            }
            _search["g_url"] = g_url
        else:
            _search["label"].append("系统漏洞")
            _search["stype"] = "os_vul"
            _search["vulns"] = {
                "name": vul_name,
                "cve": numbering,
                "service": {
                    "info": "",
                    "host": "",
                    "proto": "",
                    "port": "",
                    "name": ""
                },
                "desc": ""
            }
        _search["cve"] = [numbering]
        _search["etype"].append("vul")
        _search["type"] = "vul"
        _search["pid"] = "UPDATE"
        _search["id"] = calc_md5(json.dumps(_search))
        return _search

    def createWeakpwd(self, host=None, port=None, service=None, user=None, passwd=None):
        """构建弱口令数据"""
        _search = copy.deepcopy(self.search)
        _search["etype"].append("vul")
        _search["label"].append("弱口令")
        _search["stype"] = "weak_pwd"
        _search["crack"] = {
            "user": user,
            "host": host,
            "password": passwd,
            "port": port,
            "service": service
        }
        _search["type"] = "vul"
        _search["pid"] = "UPDATE"
        _search["id"] = calc_md5(json.dumps(_search))
        return _search

    def createMisSensitive(self, dataType=None, keyword=None, g_url=None):
        """构建篡改数据、敏感词"""
        _search = copy.deepcopy(self.search)
        if dataType == 'mis':
            _search["label"].append("恶意篡改")
            _search["stype"] = "mis"
            _search["type"] = "threat"
            _search["etype"].append("web_threat")
        else:
            _search["keyword"] = keyword
            _search["label"].append("敏感词")
            _search["stype"] = "sensitive"
            _search["type"] = "content"
            _search["etype"].append("content")

        _search["g_url"] = g_url
        _search["url"].append(g_url)
        _search["pid"] = "UPDATE"
        _search["id"] = calc_md5(json.dumps(_search))
        return _search

    def checkVulEventsFromXlsx(self):
        """验证Excel中 脆弱性信息填写是否准确"""
        vuls = []
        try:
            table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"脆弱性日志导入模板"]
        except:
            print "vul error"
            return []
        row_number = 0
        for types in table.rows:
            row_number = row_number + 1
            try:
                # 先判断是不是第一行 如果是第一行 跳过
                if row_number == 1:
                    continue

                if not types[0].value:
                    vuls.append(row_number)
                    continue

                if not types[1].value:
                    vuls.append(row_number)
                    continue

                if not types[2].value:
                    vuls.append(row_number)
                    continue

                if not types[3].value:
                    vuls.append(row_number)
                    continue

                if str(types[3].value) == "系统漏洞" or str(types[3].value) == "web漏洞":
                    if not types[4].value:
                        vuls.append(row_number)
                        continue
                    if str(types[3].value) == "web漏洞" and not types[11].value:
                        vuls.append(row_number)
                        continue

                elif str(types[3].value) == "弱口令":
                    if not types[6].value:
                        vuls.append(row_number)
                        continue

                    if not types[7].value:
                        vuls.append(row_number)
                        continue

                    if not types[8].value:
                        vuls.append(row_number)
                        continue

                    if not types[9].value:
                        vuls.append(row_number)
                        continue

                    if not types[10].value:
                        vuls.append(row_number)
                        continue

                else:
                    vuls.append(row_number)
                    continue

            except:
                vuls.append(row_number)
                continue
        return vuls

    def checkAttackEventsFromXlsx(self):
        """验证Excel中 攻击信息填写是否准确"""
        attack = []
        try:
            table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"攻击日志导入模板"]
        except:
            print "attack error"
            return []
        row_number = 0
        for types in table.rows:
            try:
                row_number = row_number + 1
                # 先判断是不是第一行 如果是第一行 跳过
                if row_number == 1:
                    continue

                if not types[0].value:
                    attack.append(row_number)
                    continue

                if not types[1].value:
                    attack.append(row_number)
                    continue

                if not types[2].value:
                    attack.append(row_number)
                    continue

                if not types[3].value:
                    attack.append(row_number)
                    continue

                if str(types[3].value) == "钓鱼":
                    if not types[3].value:
                        attack.append(row_number)
                        continue
                elif str(types[3].value) == "挂马":
                    if not types[6].value:
                        attack.append(row_number)
                        continue
                elif str(types[3].value) == "暗链":
                    if not types[6].value:
                        attack.append(row_number)
                        continue
                elif str(types[3].value) == "篡改":
                    if not types[6].value:
                        attack.append(row_number)
                        continue
                else:
                    attack.append(row_number)
                    continue
            except:
                attack.append(row_number)
                continue
        return attack

    def checkContentEventsFromXlsx(self):
        """验证Excel中 内容信息填写是否准确"""
        content = []
        try:
            table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"内容日志导入模板"]
        except:
            print "content error"
            return []
        row_number = 0
        for types in table.rows:
            try:
                row_number = row_number + 1
                # 先判断是不是第一行 如果是第一行 跳过
                if row_number == 1:
                    continue

                if not types[0].value:
                    content.append(row_number)
                    continue

                if not types[1].value:
                    content.append(row_number)
                    continue

                if not types[2].value:
                    content.append(row_number)
                    continue

                if not types[3].value:
                    content.append(row_number)
                    continue

                if str(types[3].value) == "敏感词":
                    if not types[4].value:
                        content.append(row_number)
                        continue
                else:
                    content.append(row_number)
                    continue
            except:
                content.append(row_number)
                continue
        return content

    def checkVisibleEventsFromXlsx(self):
        """验证Excel中 可用性信息填写是否准确"""
        visible = []
        try:
            table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"可用性日志导入模板"]
        except:
            print "Visible error"
            return []
        row_number = 0
        for types in table.rows:
            try:
                row_number = row_number + 1
                # 先判断是不是第一行 如果是第一行 跳过
                if row_number == 1:
                    continue

                if not types[0].value:
                    visible.append(row_number)
                    continue

                if not types[1].value:
                    visible.append(row_number)
                    continue

                if not types[2].value:
                    visible.append(row_number)
                    continue

                if str(types[2].value).lower() in ["http", "ping", "dns"]:
                    if not types[3].value:
                        visible.append(row_number)
                        continue
                    if not types[4].value:
                        visible.append(row_number)
                        continue
                else:
                    visible.append(row_number)
                    continue
            except:
                visible.append(row_number)
                continue
        return visible

    def getVulEventsFromXlsx(self):
        """
            解析xlsx中的系统漏洞、WEB漏洞、弱口令数据
                types[0].value 网站名称         types[5].value 漏洞编号
                types[1].value 网站URL
                types[2].value 告警等级         types[6].value IP
                types[3].value 日志类型         types[7].value 端口          types[9].value 账户
                types[4].value 漏洞名称         types[8].value 服务          types[10].value 口令
        """
        vuls = []
        table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"脆弱性日志导入模板"]
        for types in table.rows:
            if str(types[3].value) == "系统漏洞":
                result = self.createVul(dataType="os_vul", vul_name=str(types[4].value), numbering=str(types[5].value))
            elif str(types[3].value) == "web漏洞":
                result = self.createVul(dataType="web_vul", vul_name=str(types[4].value),
                                        numbering=str(types[5].value), g_url=str(types[11].value))
            elif str(types[3].value) == "弱口令":
                result = self.createWeakpwd(host=str(types[6].value), port=str(types[7].value),
                                            service=str(types[8].value), user=str(types[9].value),
                                            passwd=str(types[10].value))
            else:
                continue
            result["site_info"]["name"] = str(types[0].value)
            result["site_info"]["level"] = 0
            if str(types[2].value) == '正常':
                result["site_info"]["level"] = 0
            elif str(types[2].value) == '低危':
                result["site_info"]["level"] = 1
            elif str(types[2].value) == '中危':
                result["site_info"]["level"] = 2
            elif str(types[2].value) == '高危':
                result["site_info"]["level"] = 3
            elif str(types[2].value) == '严重':
                result["site_info"]["level"] = 4
            result["site"] = str(types[1].value)
            result["url"] = [str(types[1].value)]
            result["level"] = result["site_info"]["level"]

            vuls.append({
                "_index": "black_web" + str(datetime.date.today()).split('-')[0],
                "_type": result['type'],
                "_id": result['id'],
                "_source": result
            })
        return vuls

    def getAttackEventsFromXlsx(self):
        """解析xlsx中的挂马、钓鱼数据"""
        attacks = []
        table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"攻击日志导入模板"]
        for types in table.rows:
            if str(types[3].value) == "钓鱼":
                result = self.createTrojanFishDarklink(dataType="phish", link=str(types[4].value))
            elif str(types[3].value) == "挂马":
                result = self.createTrojanFishDarklink(dataType="trojan", g_url=str(types[6].value))
            elif str(types[3].value) == "暗链":
                result = self.createTrojanFishDarklink(dataType="darklink",
                                                       link=str(types[5].value), g_url=str(types[6].value))
            elif str(types[3].value) == "篡改":
                result = self.createMisSensitive(dataType="mis", g_url=str(types[6].value))
            else:
                continue
            result["site_info"]["name"] = str(types[0].value)
            result["site_info"]["level"] = 0
            if str(types[2].value) == '正常':
                result["site_info"]["level"] = 0
            elif str(types[2].value) == '低危':
                result["site_info"]["level"] = 1
            elif str(types[2].value) == '中危':
                result["site_info"]["level"] = 2
            elif str(types[2].value) == '高危':
                result["site_info"]["level"] = 3
            elif str(types[2].value) == '严重':
                result["site_info"]["level"] = 4
            result["site"] = str(types[1].value)
            result["url"] = [str(types[1].value)]
            result["level"] = result["site_info"]["level"]
            attacks.append({
                "_index": "black_web" + str(datetime.date.today()).split('-')[0],
                "_type": result['type'],
                "_id": result['id'],
                "_source": result
            })
        return attacks

    def getContentEventsFromXlsx(self):
        """解析xlsx中的篡改、敏感词数据"""
        contents = []
        table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"内容日志导入模板"]
        for types in table.rows:
            if str(types[3].value) == "敏感词":
                result = self.createMisSensitive(dataType="sensitive", keyword=str(types[5].value),
                                                 g_url=str(types[4].value))
            else:
                continue

            result["site_info"]["name"] = str(types[0].value)
            result["site_info"]["level"] = 0
            if str(types[2].value) == '正常':
                result["site_info"]["level"] = 0
            elif str(types[2].value) == '低危':
                result["site_info"]["level"] = 1
            elif str(types[2].value) == '中危':
                result["site_info"]["level"] = 2
            elif str(types[2].value) == '高危':
                result["site_info"]["level"] = 3
            elif str(types[2].value) == '严重':
                result["site_info"]["level"] = 4
            result["site"] = str(types[1].value)
            result["url"] = [str(types[1].value)]

            if str(types[3].value) == "敏感词":
                result["url"].append(str(types[4].value))

            result["level"] = result["site_info"]["level"]
            contents.append({
                "_index": "black_web" + str(datetime.date.today()).split('-')[0],
                "_type": result['type'],
                "_id": result['id'],
                "_source": result
            })
        return contents

    def getVisibleEventsFromXlsx(self):
        """解析xlsx中的可用性数据"""
        visibles = []
        table = load_workbook(os.path.join(config.UPLOAD_EVENTS_SAVE, 'events.xlsx'))[u"可用性日志导入模板"]
        for types in table.rows:
            if str(types[2].value) in ["http", "ping", "dns"]:
                result = self.createVisible(dataType=str(types[2].value).lower(), resTime=str(types[3].value),
                                            lastRes=str(types[4].value))
                result["site_info"]["name"] = str(types[0].value)
                result["site"] = str(types[1].value)
                result["url"] = [str(types[1].value)]
                visibles.append({
                    "_index": "black_web" + str(datetime.date.today()).split('-')[0],
                    "_type": result['type'],
                    "_id": result['id'],
                    "_source": result
                })
        return visibles


def is_virusname(vxname):
    # 判断一个字符串是否是病毒名
    regex = re.compile(
        r'^(?:' + config.TYPE_STR + ')(?:\[(' + config.BEHA_STR + ')\])?/(?:' + config.PLAT_STR + ')((?:\.[\w-]+){1,2})$')
    return True if regex.match(vxname) else False


def if_null(data, fields):
    """判断字段是否为空"""
    flag = True
    msg = ""
    for field in fields:
        if not data.get(field, None):
            flag = False
            msg = field + '不能为空'
            return flag, msg
    return flag, msg


"""资产数据生成树 """


def killNoneChildren(data):
    for i in data:
        if len(i["children"]) == 0:
            i.pop("children")
        else:
            killNoneChildren(i["children"])


def makeTree(tree, data):
    for i in tree:
        for j in data:
            if i["id"] == j["parent_node_id"]:
                j["parent_node_id"] = -1
                i["children"].append({
                    "id": j["node_id"],
                    "label": j["node_name"],
                    "value": j["node_id"],
                    "children": []
                })
                makeTree(i["children"], data)


def findTopNode(data, value):
    treeTop = []
    for i in data:
        if i["parent_node_id"] == value:
            treeTop.append({
                "id": i["node_id"],
                "label": i["node_name"],
                "value": i["node_id"],
                "children": []
            })
    makeTree(treeTop, data)
    killNoneChildren(treeTop)
    return treeTop


class SignalProcess(object):
    def __init__(self):
        self.exit = False
        signal.signal(signal.SIGTERM, self.__onSignal)

    def __onSignal(self, num, frame):
        self.exit = True

    def exitOnSignal(self):
        if self.exit:
            sys.exit(0)


# class CJsonEncoder(json.JSONEncoder):
#     def default(self, obj):
#         if isinstance(obj, datetime.date):
#             return obj.strftime('%Y-%m-%d %H:%M:%S')
#         else:
#             return json.JSONEncoder.default(self, obj)


class EncryptString(object):
    """字符串加密
    1. 在字符中循环插如扰乱字符
    2. 修改字符的排列顺序
    3. 重复多次 步骤1&2来进行加密"""

    def __init__(self, depth=5):
        self.depth = depth  # 加密次数
        self.inserts = [  # 插入的字符
            string.digits,
            string.ascii_lowercase,
            string.punctuation
        ]

    def encrypt_md5(self, encstr):
        """返回MD5 (插值并打乱顺序后的字符串MD5)"""
        return calc_md5(self.encrypt(encstr))

    def encrypt(self, encstr):
        """返回插值并打乱顺序后的字符串"""
        res = encstr
        depth = 1
        while depth <= self.depth:
            depth += 1
            res = self._encrypt_upset(self._encrypt_insert(res, self.inserts[depth % len(self.inserts)]))
        return res

    def _encrypt_insert(self, encstr, insertstr):
        '''向字符中循环插入字符
        ABC --> A!B"C#
        '''
        encstrs = [c for c in encstr]
        gaps = [c for c in insertstr]
        res = ''
        for i in range(len(encstrs)):
            res += encstrs[i] + gaps[i % len(gaps)]
        return res

    def _encrypt_upset(self, encstr):
        '''打乱字符顺序
        ABC123 --> A1B2C3
        ABCD123 --> A1B2C3D
        '''
        encstrs = [c for c in encstr]
        encstrs_len = len(encstrs)
        lefts = encstrs[:encstrs_len / 2]
        rights = encstrs[encstrs_len - encstrs_len / 2:]
        centers = encstrs[encstrs_len / 2:encstrs_len - encstrs_len / 2]
        res = ''
        for i in range(len(lefts)):
            res += lefts[i] + rights[i]
        res += centers[0] if centers else ''
        return res


def get_logger(filename, level=logging.INFO, split='time', backupCount=10, encoding='utf-8'):
    '''获取logger'''
    dirname = os.path.dirname(filename)
    if dirname and not os.path.exists(dirname):
        os.makedirs(dirname)
    logger = logging.getLogger(filename)
    if split == 'time':
        handler = logging.handlers.TimedRotatingFileHandler(filename, when='W0', backupCount=backupCount,
                                                            encoding=encoding)
    else:
        handler = logging.handlers.RotatingFileHandler(filename, maxBytes=100 * 1024 * 1024, backupCount=backupCount,
                                                       encoding=encoding)
    handler.setLevel(level)
    handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
    logger.addHandler(handler)
    logger.setLevel(level)
    return logger


def coding(source, coding='utf-8'):
    '''将字符转换到指定编码'''
    if coding == 'utf-8':
        if type(source).__name__ == 'str':
            try:
                return unicode(source, 'utf-8')  # ' ASCII 2 UTF-8 '
            except:
                return unicode(source, 'gbk')  # ' GBK 2 UTF-8 '
        elif type(source).__name__ == 'unicode':
            return source  # ' UTF-8 2 UTF-8 '
    elif coding == 'gbk':
        if type(source).__name__ == 'str':
            try:
                return unicode(source, 'utf-8').encode('gbk')  # ' ASCII 2 GBK '
            except:
                return source  # ' GBK 2 GBK '
        elif type(source).__name__ == 'unicode':
            return source.encode('gbk')  # ' UTF-8 2 GBK '
    elif coding == 'ascii':
        if type(source).__name__ == 'str':
            try:
                return unicode(source, 'utf-8').encode('utf-8')  # ' ASCII 2 ASCII '
            except:
                return source.decode('gbk').encode('utf-8')  # ' GBK 2 ASCII '
        elif type(source).__name__ == 'unicode':
            return source.encode('utf-8')  # ' UTF-8 2 ASCII '
    elif coding == 'st2':
        return ' '.join([bin(ord(c)).replace('0b', '') for c in source])
    elif coding == '2ts':
        return ''.join([chr(i) for i in [int(b, 2) for b in source.split(' ')]])
    else:
        return source  # unknown


def remove_path(path):
    """删除文件或目录"""
    if not path:
        return
    if os.path.isdir(path):
        for root, dirs, files in os.walk(path, topdown=False):
            for name in files:
                os.remove(os.path.join(root, name))
            for name in dirs:
                os.rmdir(os.path.join(root, name))
        os.rmdir(path)
    else:
        os.remove(path)


def upload_file(key, savedir, savename):
    '''上传文件'''
    upfile = request.files.get(key, None)
    if not upfile:
        return False
    name = savename if savename else upfile.filename
    name = name.replace('\\', '_').replace('/', '_').replace('..', '_')
    savepath = os.path.join(savedir, name)
    upfile.save(savepath)
    return savepath


def download_file(basedir, filename):
    return send_from_directory(basedir, filename)


def response_file(content, attaname, mimetype='application/octet-stream'):
    """响应文件"""
    resp = Response(content, mimetype=mimetype)
    if attaname:
        resp.headers['Content-Disposition'] = 'attachment;filename=' + attaname
    return resp


def sitemap():
    """以html输出当前APP的url"""
    output = []
    for rule in current_app.url_map.iter_rules():
        methods = ' , '.join(rule.methods)
        arg_name = []
        options = {}
        for arg in rule.arguments:
            options[arg] = "1010101" + str(len(arg_name))
            arg_name.append(arg)
        url = url_for(rule.endpoint, **options)
        for i in range(len(arg_name)):
            url = url.replace("1010101" + str(i), '&lt;' + arg_name[i] + '&gt;')
        output.append((rule.endpoint, methods, urllib.unquote(url)))
    return """<style>td,th{padding:3px 20px; border-width:0px;}</style>
            <table><tr align='left'><th>Endpoint</th><th>Method</th><th>URL</th></tr>""" + \
           ''.join(["<tr><td>" + d[0] + "</td><td>" + d[1] + "</td><td>" + d[2] + \
                    "</td></tr>" for d in sorted(output)]) + "</table>"


def jsonp(func):
    """包装JSONP请求"""

    @wraps(func)
    def decorated_function(*args, **kwargs):
        callback = request.args.get('callback', False)
        data = func(*args, **kwargs)
        if callback:
            content = callback + '(' + data + ')'
            mimetype = 'application/javascript'
            return current_app.response_class(content, mimetype=mimetype)
        else:
            return data

    return decorated_function


def CORS(vt=None, methods=None, headers=None, max_age=21600, attach_to_all=True, automatic_options=True):
    """处理跨域资源共享"""
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(vt, basestring):
        vt = ', '.join(vt)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp
            h = resp.headers
            h['Access-Control-Allow-vt'] = vt
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)

    return decorator


def parse_rangetime(startTimeStr=None, endTimeStr=None):
    """解析时间范围"""
    data = {
        "startTime": None, "endTime": None,  # 开始时间 结束时间
        "tochar": None, "trunc": None,  # 日期简写形式 统计周期
        "dayCount": None  # 相差天数
    }
    # 时间默认值
    data['endTime'] = datetime.date.today()
    data['startTime'] = data['endTime'] - datetime.timedelta(days=1)
    # 指定的时间范围
    if startTimeStr:
        data['startTime'] = datetime.date(*time.strptime(startTimeStr, '%Y-%m-%d')[:3])
    if endTimeStr:
        data['endTime'] = datetime.date(*time.strptime(endTimeStr, '%Y-%m-%d')[:3])
        # 结束时间+1
        data['endTime'] = data['endTime'] + datetime.timedelta(days=1)

    # 开始与结束相差的天数
    data['dayCount'] = (data['endTime'] - data['startTime']).days
    # 选择查询方式
    if 0 < data['dayCount'] <= 2:
        # 按照小时查询
        data['tochar'] = 'HH24'
        data['trunc'] = 'hour'
    elif 2 < data['dayCount'] <= 62:
        # 按照天查询
        data['tochar'] = 'MM-DD'
        data['trunc'] = 'day'
    elif 62 < data['dayCount'] <= 367:
        # 按照天查询
        data['tochar'] = 'MM'
        data['trunc'] = 'month'
    else:
        return False  # 失败(开始时间 在 结束时间之后 或者 时间范围过长)
    return data


def get_datetime_by_truncs(datestr):
    """获取可导出的报告列表"""
    calendar.setfirstweekday(calendar.MONDAY)
    today = datetime.date.today()
    datearr = [int(t) for t in datestr.split('-')][:3]
    if datearr[0] > today.year or datearr[1] < 1 or datearr[1] > 12 or (
            datearr[0] == today.year and datearr[1] > today.month):
        return '{"status":"error"}'
    # 可生成的年报

    report_year = {
        'name': "%s年" % (datearr[0]),
        'startTime': "%s-01-01" % (datearr[0],),
        'endTime': (datetime.datetime.today() - timedelta(days=1)).strftime("%Y-%m-%d") if int(
            time.time() - 60 * 60 * 24) < int(
            time.mktime(time.strptime("%s-12-31" % (datearr[0],), "%Y-%m-%d"))) else "%s-12-31" % (datearr[0],)
    }
    # 可生成的月报
    report_month = {
        'name': "%s年%s月" % (datearr[0], datearr[1]),
        'startTime': "%s-%02d-01" % (datearr[0], datearr[1]),
        'endTime': (datetime.datetime.today() - timedelta(days=1)).strftime("%Y-%m-%d") if int(
            time.time() - 60 * 60 * 24) < int(time.mktime(
            time.strptime("%s-%02d-%02d" % (datearr[0], datearr[1], max(calendar.monthcalendar(*datearr[:2])[-1])),
                          "%Y-%m-%d"))) else "%s-%02d-%02d" % (
            datearr[0], datearr[1], max(calendar.monthcalendar(*datearr[:2])[-1]))
    }
    # 可生成的周报
    report_week = []
    for weekarr in calendar.monthcalendar(*datearr[:2]):
        if weekarr[0] == 0:
            continue  # 当前周的第一天是上个月的不算进本月
        startTime = "%s-%02d-%02d" % (datearr[0], datearr[1], weekarr[0])
        if weekarr.count(0) == 0:
            endTime = "%s-%02d-%02d" % (datearr[0], datearr[1], weekarr[6])
        elif datearr[1] == 12:
            endTime = "%s-01-%02d" % (datearr[0] + 1, weekarr.count(0))
        else:
            endTime = "%s-%02d-%02d" % (datearr[0], datearr[1] + 1, weekarr.count(0))
        report_week.append({
            'name': "%s年第%s周" % (
                datearr[0], time.strftime("%W", datetime.datetime.strptime(startTime, "%Y-%m-%d").timetuple())),
            'startTime': startTime,
            'endTime': endTime,
            'timeStamp': 'week'
        })
    # 可生成的日报
    report_day = {
        'name': "%s年%s月%s日" % (datearr[0], datearr[1], datearr[2]),
        'startTime': "%s-%02d-%02d" % (datearr[0], datearr[1], datearr[2]),
        'endTime': "%s-%02d-%02d" % (datearr[0], datearr[1], datearr[2])
    }
    # 返回数据
    return json.dumps({
        'status': 'success',
        'years': report_year,
        'months': report_month,
        # 'weeks': report_week,
        'days': report_day
    })


def calc_md5(data_buffer):
    """计算MD5"""
    md5 = hashlib.md5()
    md5.update(data_buffer)
    return md5.hexdigest().upper()


def calc_sha1(data_buffer):
    """计算SHA1"""
    sha1 = hashlib.sha1()
    sha1.update(data_buffer)
    return sha1.hexdigest().upper()


def calc_sha256(data_buffer):
    """计算SHA256"""
    sha256 = hashlib.sha256()
    sha256.update(data_buffer)
    return sha256.hexdigest().upper()


def calc_sha512(data_buffer):
    """计算SHA512"""
    sha512 = hashlib.sha512()
    sha512.update(data_buffer)
    return sha512.hexdigest().upper()


def calc_crc32(data_buffer):
    """计算CRC32"""
    crc = binascii.crc32(data_buffer)
    if crc >= 0:
        s = "%X" % crc
        s = "%s%s" % ((8 - len(s)) * '0', s)
        return s
    else:
        s = "%X" % (~crc ^ 0xffffffff)
        s = "%s%s" % ((8 - len(s)) * '0', s)
        return s


def is_chinese(uchar):
    """判断一个unicode是否是汉字"""
    if uchar:
        for i in uchar:
            if i >= u'\u4e00' and i <= u'\u9fa5':
                return True
    return False


def get_event_ids(event_ids):
    """批量获取事件信息"""
    es = Elasticsearch(config.ES_ADDR, timeout=120)
    es_data = event_ids
    if len(es_data) > 5000:
        result = []
        res_sum = []
        for j in range(len(es_data) / 5000):
            if (j + 1) * 5000 > len(es_data):
                save_event_ids = es_data[(j) * 5000:len(es_data)]
            else:
                save_event_ids = es_data[(j) * 5000:(j + 1) * 5000]
            for i in range(len(save_event_ids) / 500):
                tmp_ids = save_event_ids[:500]
                event_ids = save_event_ids[500:]
                search_dict = {
                    "sort": {
                        "ts": {
                            "order": "desc"
                        }
                    },
                    "query": {
                        "bool": {
                            "minimum_should_match": 1,
                            "should": []
                        }
                    }
                }
                for id in tmp_ids:
                    search_dict['query']['bool']['should'].append({"query_string": {"query": "id:%s" % id}})
                search_dict['from'] = i * 500
                search_dict['size'] = len(tmp_ids)
                res = es.search(index=['htc'], body=search_dict)['hits']['hits']
                res_sum = res_sum + res
            result = result + res_sum
        return json.dumps({"status": "success", "data": result, 'total': len(result)})
    else:
        result = []
        for i in range(len(event_ids) / 500 + 1):
            tmp_ids = event_ids[:500]
            event_ids = event_ids[500:]

            search_dict = {
                "sort": {
                    "ts": {
                        "order": "desc"
                    }
                },
                "query": {
                    "bool": {
                        "minimum_should_match": 1,
                        "should": []
                    }
                }
            }

            for id in tmp_ids:
                search_dict['query']['bool']['should'].append({"query_string": {"query": "id:%s" % id}})
            search_dict['from'] = i * 500
            search_dict['size'] = len(tmp_ids)
            result = result + es.search(index=['htc'], body=search_dict)['hits']['hits']
        return json.dumps({"status": "success", "data": result, 'total': len(result)})


# 压缩文件夹
def zip_dir(dirname, zipfilename, zipPath):
    filelist = []
    if os.path.isfile(dirname):
        filelist.append(dirname)
    else:
        for root, dirs, files in os.walk(dirname):
            for name in files:
                filelist.append(os.path.join(root, name))

    zf = zipfile.ZipFile(os.path.join(zipPath, zipfilename), "w", zipfile.zlib.DEFLATED, allowZip64=True)
    for tar in filelist:
        arcname = tar[len(dirname):]
        zf.write(tar, arcname)
    zf.close()


# 安全事件搜索框 转义字符
def needs_escaping(character, escape_chars=False):
    if not escape_chars:
        escape_chars = {
            '\\': True, '+': True, '-': True, '!': True,
            '(': True, ')': True, '^': True,
            '[': True, ']': True, '\"': True, '{': True,
            '}': True, '~': True, '?': True,
            '|': True, '&': True, '/': True
        }
    else:
        escape_chars = {
            '\\': True, '+': True, '-': True, '!': True,
            '(': True, ')': True, '^': True, ':': True,
            '[': True, ']': True, '\"': True, '{': True,
            '}': True, '~': True, '?': True,
            '|': True, '&': True, '/': True
        }
    return escape_chars.get(character, False)


def do_escaping(field, data=False):
    if not field:
        return field
    sanitized = ''
    for character in field:
        if needs_escaping(character, data):
            sanitized += '\\%s' % character
        else:
            sanitized += character
    return sanitized


# 判断字符串中是否存在中文
def contain_zh(word):
    word = word.decode()
    return True if re.compile(u'[\u4e00-\u9fa5]+').search(word) else False


# 处理从搜索框传入的字符 对其进行转义
def deal(field):
    if field[0] == '"' and field[-1] == '"':
        if ':\\' in field[1:-1] or '://' in field[1:-1]:
            tmp_field = '"' + do_escaping(field[1:-1], True) + '"'
        else:
            tmp_field = field
    else:
        if len(field.split(':')) >= 3:
            tmp_field = field.split(':')[0] + ':' + do_escaping(':'.join(field.split(':')[1:]), True)
        elif "https://" in field or "http://" in field:
            # field = "url:" + field
            # tmp_field = field.split(':')[0] + ':' + do_escaping(':'.join(field.split(':')[1:]), True)
            tmp_field = '"' + do_escaping(field, True) + '"'
        elif ":" not in field and '*' != field:
            # 判断是否是中文或者是* 中文前后不加 *
            # 判断是否存在冒号 指的是查询条件是否是key:value形式的
            # 判断是否是* 原因是 *** 查询不出结果
            # 病毒名与
            if not contain_zh(field) and not is_virusname(field):
                tmp_field = "*" + do_escaping(field) + "*"
            else:
                if is_virusname(field):
                    tmp_field = '"' + field + '"'
                else:
                    tmp_field = field
        else:
            tmp_field = do_escaping(field)

    if len(field.split('.')) > 1 and field.split('.')[0] in config.NESTED_LIST:
        return {"nested": {"path": field.split('.')[0],
                           "query": {"bool": {"must": [{"query_string": {"query": tmp_field}}]}}}}
    else:
        return {"query_string": {"query": tmp_field}}


def logic(field, s_type, field_logic, s_symbol):
    """
        :param field: 带有 比较运算符的字段以及值
        :param s_type: 查询的类型 NOT AND OR
        :param field_logic: 全局变量 类型是字典 装处理之后的比较运算符 以及值
        :return: 返回更新之后的 field_logic
    """
    com = {
        "gte": ">=",
        "gt": ">",
        "lte": "<=",
        "lt": "<"
    }
    key = field.split(com[s_symbol])[0].strip()
    value = field.split(com[s_symbol])[1].strip()

    if key in ['ip', 'src.ip', 'dst.ip']:
        if s_symbol in ['gte', 'gt']:
            s_symbol = 'from'
        else:
            s_symbol = 'to'

    if s_type == "NOT" or s_type == 'AND':  # 处理
        if key not in field_logic:
            field_logic[key] = {}
        field_logic[key][s_symbol] = value
    else:
        if key not in field_logic['should']:
            field_logic["should"][key] = {}
        field_logic["should"][key][s_symbol] = value
    return field_logic


# 这俩函数 用来判断ip是否是内网IP
def ip_into_int(ip):
    return reduce(lambda x, y: (x << 8) + y, map(int, ip.split('.')))


def is_internal_ip(ip):
    ip = ip_into_int(ip)
    net_a = ip_into_int('10.255.255.255') >> 24
    net_b = ip_into_int('172.31.255.255') >> 20
    net_c = ip_into_int('192.168.255.255') >> 16
    return ip >> 24 == net_a or ip >> 20 == net_b or ip >> 16 == net_c


# 分割病毒名，获取类型、平台、家族、行为
def extract_vxname_detail(vxname):
    if vxname.upper() in ['N/A', 'NONE', 'NONE/NONE', 'N', 'A']:
        return {"virus_type": '', "virus_platform": '', "virus_family": '', "virus_behaviors": ''}

    malware_type = ''
    malware_flatform = ''
    malware_family = ''
    malware_behaviors = []
    state = 0
    for i in vxname:
        if state == 0:  # type
            malware_family += i
            if i == '/':
                state = 11
                continue
            elif i == '[':
                state = 12
                continue
            else:
                malware_type += i
        elif state == 11:  # platform
            malware_family += i
            if i == '.':
                state = 2
                continue
            else:
                malware_flatform += i
        elif state == 12:  # platform
            malware_family += i
            if i == '.':
                state = 2
                continue
            elif i == '/':
                state = 13
                continue
            else:
                pass
        elif state == 13:  # platform
            malware_family += i
            if i == '.':
                state = 2
                continue
            else:
                malware_flatform += i
        elif state == 2:  # family
            if i == '.':
                state = 3
                continue
            else:
                malware_family += i
        elif state == 3:  # version
            if i == '[':
                malware_family += i
                state = 4
                continue
        elif state == 4:  # behavior
            malware_family += i
        else:
            continue
    pos1 = malware_family.find('[')
    pos2 = malware_family.find(']')
    if pos1 >= 0 and pos2 >= 0:
        behavior = malware_family[pos1 + 1: pos2]
        malware_behaviors = re.split("[:,]", behavior)
    return {"virus_type": malware_type, "virus_platform": malware_flatform, "virus_family": malware_family,
            "virus_behaviors": malware_behaviors}


# 关联图加
def make_associat(source_index, target_index, data_list):
    data_list.append("%s-%s" % (source_index, target_index))


# 引擎调度通信函数
def policy_add_sites(send_data):
    u"""引擎调度接口."""
    requrl = config.ENGINE_URL
    send_data_json = json.dumps(send_data)
    ret = requests.post(requrl, data=send_data_json)
    return ret.content


# 连接where 后面的 and 或者 or 条件
def getlinkdict(data, type):
    i = 0
    msg = ''
    j = 0
    for key,values in  data.items():
        while '' in values:
            values.remove('')
        if len(values) == 0:
           keys = key
           j += 1
        if len(values) >0:
            if i == 0 :
                if len(values) == 1:
                    msg = 'where ' +key+  ' in '+ str(tuple(values))[:-2]+')'
                    i += 1
                else: 
                    msg = 'where ' +key+  ' in '+ str(tuple(values))
                    i += 1
            else :
                if len(values) == 1:
                    msg = msg+ ' and '+key+ ' in ' + str(tuple(values))[:-2]+')'
                else: 
                    msg = msg+ ' and '+key+ ' in ' + str(tuple(values)) 
    if type == 'os_vul':
        pass
    else:
       if j >= 1 and j < 3:
            msg = msg + ' and ' + keys + ' in (\'\')'                     
    return  msg  


# 统计返回的数据长度
def countNum(data):
    # selecturl = ''
    selectweb = ''
    for (index, item) in enumerate(data):
        if (index == 0):
            if len(item['website']) > 0:
                selectweb = """where (risk_id = '%s' and risk_type= '%s' and website_id in %s and node_id in %s)""" % (
                    str(item['risk']), str(item['risktype']),
                    str(item['website']).replace('[', '(').replace(']', ')'),
                    str(item['node']).replace('[', '(').replace(']', ')'))
            else:
                selectweb = """where (risk_id = '%s' and risk_type = '%s')""" % (
                    str(item['risk']), str(item['risktype']))
        else:
            if len(item['website']) > 0:
                selectweb += """or (risk_id = '%s'  and risk_type = '%s' and website_id in %s and node_id in %s)""" % (
                    str(item['risk']), str(item['risktype']),
                    str(item['website']).replace('[', '(').replace(']', ')'),
                    str(item['node']).replace('[', '(').replace(']', ')'))
            else:
                selectweb += """or (risk_id = '%s'  and risk_type = '%s')""" % (
                    str(item['risk']), str(item['risktype']))
    return selectweb



def handleData(data):
    dataval = {
      'website_id': [],
      'dept_id': [],
      'affect_web': [],
    }
    for item in data:
        dataval['website_id'].append(item['website_id'])
        dataval['dept_id'].append(item['dept_id'])
        dataval['affect_web'].append(item['affect_web'])
    while None in dataval['website_id']:
        dataval['website_id'].remove(None)
    while None in dataval['dept_id']:
        dataval['dept_id'].remove(None)
    while None in dataval['affect_web']:
        dataval['affect_web'].remove(None)
    dataval['website_id'] = list(set(dataval['website_id'])) 
    dataval['dept_id'] = list(set(dataval['dept_id']))  
    dataval['affect_web'] = list(set(dataval['affect_web'])) 
    return dataval


# # 连接where 条件
# def getlinkdata(data):
#     datamsg = {}
#     msg1 = ''
#     for key,values in  data.items():
#         if len(values) >0:
#             if len(values) == 1:
#                 msg1 = ' where ' + key + ' in ' + str(tuple(values))[:-2]+') '
#             else: 
#                 msg1 = ' where ' + key + ' in ' + str(tuple(values))    
#             datamsg[key] = msg1 
#             msg1 = '' 
#         else:
#             datamsg[key] = ''                        
#     return  datamsg



# 连接 or 条件
def getlinkOr(newdata,olddata):
    i = 0
    j = 0
    msg = ''
    for key, values in  olddata.items():
        if (len(values)) > 0:
            j += 1
    if j == 0:
        for key, values in  newdata.items():
            if len(values) >0:
                if i == 0 :
                    if len(values) == 1:
                        msg ='  where  ' +  key+  '  in '+ str(tuple(values))[:-2]+')'
                        i += 1
                    else: 
                        msg = '  where ' +key+  '  in  '+ str(tuple(values))
                        i += 1  
    else:                 
        for key,values in  newdata.items():
            if len(values) >0:
                if i == 0 :
                    if len(values) == 1:
                        msg ='  or  ' +  key+  '  in '+ str(tuple(values))[:-2]+')'
                        i += 1
                    else: 
                        msg = '  or ' +key+  '  in  '+ str(tuple(values))
                        i += 1             
    return  msg






def init_logger(filename,
                level=logging.INFO,
                format_str="%(asctime)s [%(levelname)s]: %(message)s",
                split_by='time', time_interval=3):
    """
    :param filename: string
    :param level: int
    :param format_str: string
    :return: logging.Logger
    """
    logger = logging.getLogger(filename)
    if 'time' == split_by:
        Rthandler = TimedRotatingFileHandler(filename, when='D', interval=time_interval, backupCount=40)
    else:
        Rthandler = RotatingFileHandler(filename, maxBytes=50 * 1024 * 1024, backupCount=40)
    Rthandler.setLevel(level)
    formatter = logging.Formatter(format_str)
    Rthandler.setFormatter(formatter)
    logger.addHandler(Rthandler)
    logger.setLevel(level)
    return logger

def anguan_encryption(data):
    md5 = hashlib.md5()
    md5.update(data)
    res=md5.hexdigest()
    sec_md5s = hashlib.md5()
    sec_md5s.update(res)
    return sec_md5s.hexdigest()

# 向第三方同步数据方法
def sync_to_anguan(module=None, opreaing=None, url=None, method=None, data={}):
    """
    :param module: 模块名称
    :param opreaing: 操作
    :param url: 请求的路径
    :param method: 请求方法
    :param data: 同步的内容
    :return: 发送成功或失败
    """
    if not module or not opreaing or not url or not method or not data:
        return False
    headers = {
        "userId": config.ATAMS_USER_ID,
        "password": config.ATAMS_PASSWORD,
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Max-Age': '86400',
        'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',
        'Access-Control-Allow-Headers': 'token, host, x-real-ip, x-forwarded-ip, accept, content-type'
    }
    headers['sign'] = anguan_encryption(base64.b64encode(config.ATAMS_SIGN_SALT+json.dumps(data,separators=(',',':'),ensure_ascii=False).replace(' ','').replace("\n", "")))
    if method == "GET":
        response = requests.get(url=url, params=json.dumps(data,separators=(',',':'),ensure_ascii=False), headers=headers).json()
    elif method == "POST":
        response = requests.post(url=url, data=json.dumps(data,separators=(',',':'),ensure_ascii=False).replace(', ',',').replace(': ',':').replace("\n", ""), headers=headers).json()
    elif method == "PUT":
        response = requests.put(url=url, data=json.dumps(data,separators=(',',':'),ensure_ascii=False), headers=headers).json()
    elif method == "DELETE":
        response = requests.delete(url=url, data=json.dumps(data,separators=(',',':'),ensure_ascii=False), headers=headers).json()
    else:
        return False
    print response,'anguan_response'
    if response["status"].lower() == "s0":
        return True
    elif response["status"].lower() in ["e1", "e2", "e3"]:
        log = init_logger(os.path.join(config.LOG_PATH, "%s_%s.log" % (module, opreaing)), split_by='time')
        log.error("""Synchronize error, 
                     because %s, original data is %s""" % (response["msg"], json.dumps(data, ensure_ascii=False)))
        return False
    elif response["status"].lower() == 'e0':
        client = KafkaClient(hosts=config.KAFKA_CLIENT)
        topic = client.topics[config.KAFKA_TOPIC]
        producer = topic.get_sync_producer()
        producer.produce(response["msg"])
        return False
    else:
        return False


# 信息加密
def compileStr(data,fields=[]):
    if len(fields)==0:
        return False,[],'请输入参数'
    for i in data:
        for j in fields:
            if i[j] is not None:
                i[j] = base64.b64encode(i[j])[::-1]
    return True,data,'加密成功'


# 机构树形结构
def uintTree(lst1):
    # 输入类型
    # lst1 = [{
    #     "key": "key1",
    #     "value": "value",
    #     "parent": "key2"
    # },{
    #     "key": "key2",
    #     "value": "value",
    #     "parent": ""
    # }]
    nodes = []
    lst2 = []
    filter(lambda x: {} if not x.get("key", "") else nodes.append(x['key']), lst1)
    parent_lst = filter(lambda x: bool(x), map(lambda x: {} if not x.get("parent", "") not in nodes else x, lst1))
    for parent in parent_lst:
        dic_tmp = {
            "parent": "",
            "children": [],
            "label": parent.get("label"),
            "key": parent.get("key")
        }
        uintTreeChild(lst1, dic_tmp)
        lst2.append(dic_tmp)
    return lst2


# 机构树形结构(辅助uintTree函数)
def uintTreeChild(lst1, dic):
    for ls in lst1:
        if dic.get("key", "") == ls.get("parent", ""):
            dic_tmp = {
                "children": [],
                "label": ls.get("label", ""),
                "key": ls.get("key", "")
            }
            dic["children"].append(dic_tmp)
    if dic["children"] == []:
        dic.pop("children")
    else:
        map(lambda x: uintTreeChild(lst1, x), dic["children"])

def validateAnguan():
    from flask import request
    if request.headers['password']!=config.ATAMS_PASSWORD:
        return 'fail'
    elif request.headers['userId']!='ATAMS':
        return 'fail'
    elif request.headers['sign']!=anguan_encryption(base64.b64encode(config.ATAMS_SIGN_SALT+request.data.replace(', ',',').replace(': ',':').replace("\n", ""))):
        return 'fail'
    else:
        return 'success'
